/// <reference path="../sinova/Polygon.ts" />

class BoxCollider extends Polygon implements ICollider {
    id: number;
    sprite: egret.DisplayObject = null;
    _lateColliders: SomeBody[] = [];


    triggers: ITriggerListener[] = [];

    _offset: egret.Point = null;
    constructor(x = 0,
        y = 0,
        points: number[][] = [],
        angle = 0,
        scale_x = 1,
        scale_y = 1,
        padding = 0,) {

        super(x, y, points, angle, scale_x, scale_y, padding);

        this.id = Physics.instance._bvh._bodies.length;
        this._offset = new egret.Point(x, y);
    }

    render(sprite: egret.Sprite) {


        if (
            this._dirty_coords ||
            this.x !== this._x ||
            this.y !== this._y ||
            this.angle !== this._angle ||
            this.scale_x !== this._scale_x ||
            this.scale_y !== this._scale_y
        ) {
            this._calculateCoords();
        }

        const coords = this._coords!;

        sprite.graphics.lineStyle(2, 0xff0000);
        sprite.graphics.moveTo(coords[0] * Physics.Scale, coords[1] * Physics.Scale);
        for (let index = 2; index < coords.length; index += 2) {
            sprite.graphics.lineTo(coords[index] * Physics.Scale, coords[index + 1] * Physics.Scale)

        }
        sprite.graphics.lineTo(coords[0] * Physics.Scale, coords[1] * Physics.Scale);

    }

    setPosition(x: number, y: number) {
        this.x = x + this._offset.x;
        this.y = y + this._offset.y;
    }

    moveCollider() {
        if (this.sprite) {
            let { x, y } = this.sprite;
            this.setPosition(x, y);
            this._bvh.remove(this, true);
            this._bvh.insert(this, true);

            this.checkCollision();
        }

    }






    move(x: number, y: number) {

        this.setPosition(x, y);
        this._bvh.remove(this, true);
        this._bvh.insert(this, true);


        this.checkCollision();
    }

    checkCollision(): void {
        let result = new Result();

        const potentials = this.potentials();
        for (const body of potentials) {


            if (this.collides(body as Polygon, result)) {

                if (this._lateColliders.indexOf(body as SomeBody) === -1) {
                    this._lateColliders.push(body as SomeBody)
                }
                else { continue; }

                for (const trigger of this.triggers) {
                    trigger.onTriggerEnter(result.a as ICollider, result.b as ICollider);

                }
            }

        }
        this._lateColliders = this._lateColliders.filter((collider) => {


            if (!this.collides(collider)) {
                for (const trigger of this.triggers) {
                    trigger.onTriggerExit(this, collider as unknown as ICollider);

                }
                return false
            }
            return true;
        })

    }


    addTriggerListener(trigger: ITriggerListener) {
        this.triggers.push(trigger);

    }


    static addCollider(sprite: egret.DisplayObject & IBody, boxCollider?: BoxCollider): ICollider {

        let { x, y, width, height } = sprite;
        let collider;
        if (boxCollider) {
            collider = boxCollider;
        } else {
            collider = new BoxCollider(0, 0, [[0, 0], [width, 0], [width, height], [0, height]]);
        }

        collider.setPosition(x, y)
        Physics.instance.insert(collider)
        if (!sprite.colliders) {
            sprite.colliders = []
        }
        sprite.colliders.push(collider);
        collider.sprite = sprite;
        sprite.moveCollider = () => {
            for (const collider of sprite.colliders) {
                collider.moveCollider();
            }
        }

        return collider;

    }


    static removeCollider(sprite: egret.DisplayObject & IBody, boxCollider: BoxCollider) {
        if (sprite != null) {
            boxCollider.sprite = null;
            sprite.colliders = sprite.colliders.filter(collider => collider.id != boxCollider.id);
        }


        Physics.instance.removeBody(boxCollider);


    }

    removeSelf() {
        BoxCollider.removeCollider(this.sprite, this);
    }
}